<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>数据转换工具</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#3B82F6',
                        secondary: '#10B981',
                        accent: '#8B5CF6',
                        neutral: '#64748B',
                    },
                    fontFamily: {
                        sans: ['Inter', 'system-ui', 'sans-serif'],
                    },
                }
            }
        }
    </script>
    <style type="text/tailwindcss">
        @layer utilities {
            .content-auto {
                content-visibility: auto;
            }
            .card-shadow {
                box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
            }
            .transition-height {
                transition: max-height 0.3s ease-in-out;
            }
        }
    </style>
</head>
<body class="bg-gray-50 min-h-screen p-4 md:p-8">
    <div class="max-w-6xl mx-auto">
        <header class="mb-8 text-center">
            <h1 class="text-[clamp(1.8rem,4vw,2.5rem)] font-bold text-gray-800 mb-2">数据转换工具</h1>
            <p class="text-gray-600">多功能数据格式转换工具，支持时间、文本、地理坐标等转换</p>
        </header>

        <main class="grid grid-cols-1 md:grid-cols-2 gap-6">
            <!-- 时间转换 -->
            <section class="bg-white rounded-xl p-6 card-shadow">
                <h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
                    <i class="fa fa-clock-o text-primary mr-2"></i>时间转换
                </h2>
                <div class="space-y-4">
                    <div>
                        <label class="block text-sm font-medium text-gray-700 mb-1">Unix时间戳</label>
                        <div class="flex gap-2">
                            <input type="text" id="unixTimeInput" placeholder="输入Unix时间戳(秒或毫秒)" class="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary outline-none transition-all">
                            <button onclick="unixToNormal()" class="bg-primary hover:bg-primary/90 text-white px-4 py-2 rounded-lg transition-all flex items-center">
                                <i class="fa fa-arrow-right mr-1"></i> 转换
                            </button>
                        </div>
                    </div>
                    <div>
                        <label class="block text-sm font-medium text-gray-700 mb-1">普通时间 (中国时区)</label>
                        <div class="flex gap-2">
                            <input type="text" id="normalTimeInput" placeholder="输入普通时间(yyyy-MM-dd HH:mm:ss)" class="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary outline-none transition-all">
                            <button onclick="normalToUnix()" class="bg-primary hover:bg-primary/90 text-white px-4 py-2 rounded-lg transition-all flex items-center">
                                <i class="fa fa-arrow-right mr-1"></i> 转换
                            </button>
                        </div>
                    </div>
                    <div>
                        <label class="block text-sm font-medium text-gray-700 mb-1">转换结果</label>
                        <textarea id="timeResult" readonly class="w-full px-4 py-2 border border-gray-300 rounded-lg bg-gray-50 min-h-[80px]" placeholder="转换结果将显示在这里..."></textarea>
                    </div>
                </div>
            </section>

            <!-- 文本合并 -->
            <section class="bg-white rounded-xl p-6 card-shadow">
                <h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
                    <i class="fa fa-align-left text-secondary mr-2"></i>文本合并
                </h2>
                <div class="space-y-4">
                    <div>
                        <label class="block text-sm font-medium text-gray-700 mb-1">输入多行文本</label>
                        <textarea id="textInput" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-secondary/50 focus:border-secondary outline-none transition-all min-h-[120px]" placeholder="输入需要合并的多行文本..."></textarea>
                    </div>
                    <div class="flex gap-2">
                        <button onclick="mergeText1()" class="flex-1 bg-secondary hover:bg-secondary/90 text-white px-4 py-2 rounded-lg transition-all flex items-center justify-center">
                            <i class="fa fa-list-ol mr-1"></i> 逗号拼接
                        </button>
                        <button onclick="mergeText2()" class="flex-1 bg-secondary hover:bg-secondary/90 text-white px-4 py-2 rounded-lg transition-all flex items-center justify-center">
                            <i class="fa fa-quote-right mr-1"></i> 单引号+逗号
                        </button>
                    </div>
                    <div>
                        <label class="block text-sm font-medium text-gray-700 mb-1">合并结果</label>
                        <textarea id="textResult" readonly class="w-full px-4 py-2 border border-gray-300 rounded-lg bg-gray-50 min-h-[80px]" placeholder="合并结果将显示在这里..."></textarea>
                    </div>
                </div>
            </section>

            <!-- 经纬度与Geohash转换 -->
            <section class="bg-white rounded-xl p-6 card-shadow">
                <h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
                    <i class="fa fa-map-marker text-accent mr-2"></i>地理编码转换
                </h2>
                <div class="space-y-4">
                    <div>
                        <label class="block text-sm font-medium text-gray-700 mb-1">经纬度 (经度,纬度)</label>
                        <div class="flex gap-2">
                            <input type="text" id="latLngInput" placeholder="例如: 116.403874,39.914885" class="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-accent/50 focus:border-accent outline-none transition-all">
                            <div class="w-32">
                                <select id="geohashPrecision" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-accent/50 focus:border-accent outline-none transition-all">
                                    <option value="8">精度: 8位</option>
                                    <option value="9">精度: 9位</option>
                                    <option value="10">精度: 10位</option>
                                    <option value="11">精度: 11位</option>
                                    <option value="12">精度: 12位</option>
                                </select>
                            </div>
                            <button onclick="latLngToGeohash()" class="bg-accent hover:bg-accent/90 text-white px-4 py-2 rounded-lg transition-all flex items-center">
                                <i class="fa fa-arrow-right mr-1"></i> 转换
                            </button>
                        </div>
                    </div>
                    <div>
                        <label class="block text-sm font-medium text-gray-700 mb-1">Geohash</label>
                        <div class="flex gap-2">
                            <input type="text" id="geohashInput" placeholder="输入Geohash值" class="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-accent/50 focus:border-accent outline-none transition-all">
                            <button onclick="geohashToLatLng()" class="bg-accent hover:bg-accent/90 text-white px-4 py-2 rounded-lg transition-all flex items-center">
                                <i class="fa fa-arrow-right mr-1"></i> 转换
                            </button>
                        </div>
                    </div>
                    <div>
                        <label class="block text-sm font-medium text-gray-700 mb-1">转换结果</label>
                        <textarea id="geoResult" readonly class="w-full px-4 py-2 border border-gray-300 rounded-lg bg-gray-50 min-h-[80px]" placeholder="地理编码转换结果将显示在这里..."></textarea>
                    </div>
                </div>
            </section>

            <!-- 坐标系转换 -->
            <section class="bg-white rounded-xl p-6 card-shadow">
                <h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
                    <i class="fa fa-exchange text-neutral mr-2"></i>坐标系转换
                </h2>
                <div class="space-y-4">
                    <div>
                        <label class="block text-sm font-medium text-gray-700 mb-1">输入坐标 (经度,纬度)</label>
                        <input type="text" id="coordInput" placeholder="例如: 116.403874,39.914885" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-neutral/50 focus:border-neutral outline-none transition-all">
                    </div>
                    <div class="grid grid-cols-2 gap-4">
                        <div>
                            <label class="block text-sm font-medium text-gray-700 mb-1">源坐标系</label>
                            <select id="sourceCoordSys" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-neutral/50 focus:border-neutral outline-none transition-all">
                                <option value="wgs84">WGS84 (GPS)</option>
                                <option value="bd09">百度坐标系 (BD09)</option>
                                <option value="gcj02">高德坐标系 (GCJ02)</option>
                            </select>
                        </div>
                        <div>
                            <label class="block text-sm font-medium text-gray-700 mb-1">目标坐标系</label>
                            <select id="targetCoordSys" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-neutral/50 focus:border-neutral outline-none transition-all">
                                <option value="bd09">百度坐标系 (BD09)</option>
                                <option value="gcj02">高德坐标系 (GCJ02)</option>
                                <option value="wgs84">WGS84 (GPS)</option>
                            </select>
                        </div>
                    </div>
                    <button onclick="convertCoordSys()" class="w-full bg-neutral hover:bg-neutral/90 text-white px-4 py-2 rounded-lg transition-all flex items-center justify-center">
                        <i class="fa fa-refresh mr-1"></i> 执行坐标系转换
                    </button>
                    <div>
                        <label class="block text-sm font-medium text-gray-700 mb-1">转换结果</label>
                        <textarea id="coordResult" readonly class="w-full px-4 py-2 border border-gray-300 rounded-lg bg-gray-50 min-h-[80px]" placeholder="坐标系转换结果将显示在这里..."></textarea>
                    </div>
                </div>
            </section>
        </main>

        <footer class="mt-12 text-center text-gray-500 text-sm">
            <p>数据转换工具 &copy; 2024 | 所有转换均在本地完成，不会上传您的数据</p>
        </footer>
    </div>

    <script>
        // 时间转换相关函数
        function unixToNormal() {
            const input = document.getElementById('unixTimeInput').value.trim();
            if (!input) return;

            let timestamp;
            // 检测是秒还是毫秒
            if (input.length === 10) {
                timestamp = parseInt(input) * 1000;
            } else if (input.length === 13) {
                timestamp = parseInt(input);
            } else {
                alert('请输入有效的Unix时间戳(10位秒或13位毫秒)');
                return;
            }

            const date = new Date(timestamp);
            // 设置为中国时区 (UTC+8)
            const chinaTime = new Date(date.getTime() + 8 * 60 * 60 * 1000);
            const formatted = formatDate(chinaTime);
            document.getElementById('timeResult').value = formatted;
            document.getElementById('normalTimeInput').value = formatted;
        }

        function normalToUnix() {
            const input = document.getElementById('normalTimeInput').value.trim();
            if (!input) return;

            // 尝试解析多种格式
            const formats = [
                'yyyy-MM-dd HH:mm:ss',
                'yyyy/MM/dd HH:mm:ss',
                'yyyy.MM.dd HH:mm:ss',
                'yyyy-MM-dd',
                'yyyy/MM/dd',
                'yyyy.MM.dd'
            ];

            let timestamp = null;
            for (const format of formats) {
                timestamp = parseDateToTimestamp(input, format);
                if (timestamp !== null) break;
            }

            if (timestamp === null) {
                alert('请输入有效的时间格式(yyyy-MM-dd HH:mm:ss)');
                return;
            }

            // 转换为UTC时间戳(秒)
            const unixSeconds = Math.floor(timestamp / 1000);
            const unixMilliseconds = timestamp;
            document.getElementById('timeResult').value = `秒级: ${unixSeconds}\n毫秒级: ${unixMilliseconds}`;
            document.getElementById('unixTimeInput').value = unixSeconds;
        }

        function formatDate(date) {
            const year = date.getUTCFullYear();
            const month = String(date.getUTCMonth() + 1).padStart(2, '0');
            const day = String(date.getUTCDate()).padStart(2, '0');
            const hours = String(date.getUTCHours()).padStart(2, '0');
            const minutes = String(date.getUTCMinutes()).padStart(2, '0');
            const seconds = String(date.getUTCSeconds()).padStart(2, '0');
            return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
        }

        function parseDateToTimestamp(dateStr, format) {
            try {
                let year, month, day, hours = 0, minutes = 0, seconds = 0;

                if (format.includes('yyyy-MM-dd HH:mm:ss')) {
                    const parts = dateStr.split(/[- :]/);
                    year = parseInt(parts[0]);
                    month = parseInt(parts[1]) - 1;
                    day = parseInt(parts[2]);
                    hours = parseInt(parts[3]) || 0;
                    minutes = parseInt(parts[4]) || 0;
                    seconds = parseInt(parts[5]) || 0;
                } else if (format.includes('yyyy/MM/dd HH:mm:ss')) {
                    const parts = dateStr.split(/[\/ :]/);
                    year = parseInt(parts[0]);
                    month = parseInt(parts[1]) - 1;
                    day = parseInt(parts[2]);
                    hours = parseInt(parts[3]) || 0;
                    minutes = parseInt(parts[4]) || 0;
                    seconds = parseInt(parts[5]) || 0;
                } else if (format.includes('yyyy.MM.dd HH:mm:ss')) {
                    const parts = dateStr.split(/[. :]/);
                    year = parseInt(parts[0]);
                    month = parseInt(parts[1]) - 1;
                    day = parseInt(parts[2]);
                    hours = parseInt(parts[3]) || 0;
                    minutes = parseInt(parts[4]) || 0;
                    seconds = parseInt(parts[5]) || 0;
                } else if (format.includes('yyyy-MM-dd')) {
                    const parts = dateStr.split('-');
                    year = parseInt(parts[0]);
                    month = parseInt(parts[1]) - 1;
                    day = parseInt(parts[2]);
                } else if (format.includes('yyyy/MM/dd')) {
                    const parts = dateStr.split('/');
                    year = parseInt(parts[0]);
                    month = parseInt(parts[1]) - 1;
                    day = parseInt(parts[2]);
                } else if (format.includes('yyyy.MM.dd')) {
                    const parts = dateStr.split('.');
                    year = parseInt(parts[0]);
                    month = parseInt(parts[1]) - 1;
                    day = parseInt(parts[2]);
                }

                const date = new Date(Date.UTC(year, month, day, hours, minutes, seconds));
                // 检查日期是否有效
                if (date.getUTCFullYear() !== year || date.getUTCMonth() !== month || date.getUTCDate() !== day) {
                    return null;
                }
                return date.getTime() - 8 * 60 * 60 * 1000; // 转换为UTC时间
            } catch (e) {
                return null;
            }
        }

        // 文本合并相关函数
        function mergeText1() {
            const input = document.getElementById('textInput').value;
            if (!input) return;

            // 按行分割并过滤空行
            const lines = input.split('\n').filter(line => line.trim() !== '');
            // 用逗号拼接
            const result = lines.join(',');
            document.getElementById('textResult').value = result;
        }

        function mergeText2() {
            const input = document.getElementById('textInput').value;
            if (!input) return;

            // 按行分割并过滤空行
            const lines = input.split('\n').filter(line => line.trim() !== '');
            // 每行用单引号包围，再用逗号拼接
            const result = lines.map(line => `'${line.trim()}'`).join(',');
            document.getElementById('textResult').value = result;
        }

        // 地理编码相关函数
        function latLngToGeohash() {
            const input = document.getElementById('latLngInput').value.trim();
            if (!input) return;

            // 支持逗号、空格或Tab分隔
            const coords = input.replace(/[\t\s]+/, ',').split(',').map(coord => parseFloat(coord.trim()));
            if (coords.length !== 2 || isNaN(coords[0]) || isNaN(coords[1])) {
                alert('请输入有效的经纬度(经度,纬度)');
                return;
            }

            const lng = coords[0];
            const lat = coords[1];
            const precision = parseInt(document.getElementById('geohashPrecision').value);

            const geohash = encodeGeohash(lng, lat, precision);
            document.getElementById('geoResult').value = geohash;
            document.getElementById('geohashInput').value = geohash;
        }

        function geohashToLatLng() {
            const geohash = document.getElementById('geohashInput').value.trim();
            if (!geohash) return;

            const [lng, lat, lngErr, latErr] = decodeGeohash(geohash);
            const result = `经度: ${lng.toFixed(6)} ±${lngErr.toFixed(6)}\n纬度: ${lat.toFixed(6)} ±${latErr.toFixed(6)}`;
            document.getElementById('geoResult').value = result;
            document.getElementById('latLngInput').value = `${lng.toFixed(6)},${lat.toFixed(6)}`;
        }

        // Geohash编码实现
        const base32 = '0123456789bcdefghjkmnpqrstuvwxyz';
        const bits = [16, 8, 4, 2, 1];

        function encodeGeohash(lng, lat, precision = 12) {
            let lngRange = [-180, 180];
            let latRange = [-90, 90];
            let geohash = '';
            let isEven = true;
            let bit = 0;
            let ch = 0;

            while (geohash.length < precision) {
                let mid;
                if (isEven) {
                    // 经度
                    mid = (lngRange[0] + lngRange[1]) / 2;
                    if (lng > mid) {
                        ch |= bits[bit];
                        lngRange[0] = mid;
                    } else {
                        lngRange[1] = mid;
                    }
                } else {
                    // 纬度
                    mid = (latRange[0] + latRange[1]) / 2;
                    if (lat > mid) {
                        ch |= bits[bit];
                        latRange[0] = mid;
                    } else {
                        latRange[1] = mid;
                    }
                }

                isEven = !isEven;
                if (bit < 4) {
                    bit++;
                } else {
                    geohash += base32[ch];
                    bit = 0;
                    ch = 0;
                }
            }

            return geohash;
        }

        function decodeGeohash(geohash) {
            let lngRange = [-180, 180];
            let latRange = [-90, 90];
            let isEven = true;

            for (let i = 0; i < geohash.length; i++) {
                const c = geohash[i];
                const idx = base32.indexOf(c);
                if (idx === -1) break;

                for (let n = 4; n >= 0; n--) {
                    const bit = (idx >> n) & 1;
                    if (isEven) {
                        // 经度
                        const mid = (lngRange[0] + lngRange[1]) / 2;
                        if (bit === 1) {
                            lngRange[0] = mid;
                        } else {
                            lngRange[1] = mid;
                        }
                    } else {
                        // 纬度
                        const mid = (latRange[0] + latRange[1]) / 2;
                        if (bit === 1) {
                            latRange[0] = mid;
                        } else {
                            latRange[1] = mid;
                        }
                    }
                    isEven = !isEven;
                }
            }

            const lng = (lngRange[0] + lngRange[1]) / 2;
            const lat = (latRange[0] + latRange[1]) / 2;
            const lngErr = lngRange[1] - lng;
            const latErr = latRange[1] - lat;

            return [lng, lat, lngErr, latErr];
        }

        // 坐标系转换相关函数
        function convertCoordSys() {
            const input = document.getElementById('coordInput').value.trim();
            if (!input) return;

            const coords = input.split(',').map(coord => parseFloat(coord.trim()));
            if (coords.length !== 2 || isNaN(coords[0]) || isNaN(coords[1])) {
                alert('请输入有效的坐标(经度,纬度)');
                return;
            }

            const source = document.getElementById('sourceCoordSys').value;
            const target = document.getElementById('targetCoordSys').value;
            let lng = coords[0];
            let lat = coords[1];

            // 如果源和目标相同，直接返回
            if (source === target) {
                document.getElementById('coordResult').value = `${lng.toFixed(6)},${lat.toFixed(6)}`;
                return;
            }

            // 根据源和目标坐标系进行转换
            if (source === 'wgs84' && target === 'gcj02') {
                [lng, lat] = wgs84ToGcj02(lng, lat);
            } else if (source === 'wgs84' && target === 'bd09') {
                [lng, lat] = wgs84ToBd09(lng, lat);
            } else if (source === 'gcj02' && target === 'wgs84') {
                [lng, lat] = gcj02ToWgs84(lng, lat);
            } else if (source === 'gcj02' && target === 'bd09') {
                [lng, lat] = gcj02ToBd09(lng, lat);
            } else if (source === 'bd09' && target === 'wgs84') {
                [lng, lat] = bd09ToWgs84(lng, lat);
            } else if (source === 'bd09' && target === 'gcj02') {
                [lng, lat] = bd09ToGcj02(lng, lat);
            }

            document.getElementById('coordResult').value = `${lng.toFixed(6)},${lat.toFixed(6)}`;
        }

        // 坐标系转换实现
        const PI = Math.PI;
        const a = 6378245.0;
        const ee = 0.00669342162296594323;
        const x_pi = PI * 3000.0 / 180.0;

        function transformLat(x, y) {
            let ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
            ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
            ret += (20.0 * Math.sin(y * PI) + 40.0 * Math.sin(y / 3.0 * PI)) * 2.0 / 3.0;
            ret += (160.0 * Math.sin(y / 12.0 * PI) + 320 * Math.sin(y * PI / 30.0)) * 2.0 / 3.0;
            return ret;
        }

        function transformLng(x, y) {
            let ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
            ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
            ret += (20.0 * Math.sin(x * PI) + 40.0 * Math.sin(x / 3.0 * PI)) * 2.0 / 3.0;
            ret += (150.0 * Math.sin(x / 12.0 * PI) + 300.0 * Math.sin(x / 30.0 * PI)) * 2.0 / 3.0;
            return ret;
        }

        function outOfChina(lng, lat) {
            return (lng < 72.004 || lng > 137.8347) || ((lat < 0.8293 || lat > 55.8271) || false);
        }

        function wgs84ToGcj02(lng, lat) {
            if (outOfChina(lng, lat)) {
                return [lng, lat];
            }
            let dLat = transformLat(lng - 105.0, lat - 35.0);
            let dLng = transformLng(lng - 105.0, lat - 35.0);
            const radLat = lat / 180.0 * PI;
            let magic = Math.sin(radLat);
            magic = 1 - ee * magic * magic;
            const sqrtMagic = Math.sqrt(magic);
            dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI);
            dLng = (dLng * 180.0) / (a / sqrtMagic * Math.cos(radLat) * PI);
            const mgLat = lat + dLat;
            const mgLng = lng + dLng;
            return [mgLng, mgLat];
        }

        function gcj02ToWgs84(lng, lat) {
            if (outOfChina(lng, lat)) {
                return [lng, lat];
            }
            let dLat = transformLat(lng - 105.0, lat - 35.0);
            let dLng = transformLng(lng - 105.0, lat - 35.0);
            const radLat = lat / 180.0 * PI;
            let magic = Math.sin(radLat);
            magic = 1 - ee * magic * magic;
            const sqrtMagic = Math.sqrt(magic);
            dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI);
            dLng = (dLng * 180.0) / (a / sqrtMagic * Math.cos(radLat) * PI);
            const mgLat = lat + dLat;
            const mgLng = lng + dLng;
            return [lng * 2 - mgLng, lat * 2 - mgLat];
        }

        function gcj02ToBd09(lng, lat) {
            const z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * x_pi);
            const theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * x_pi);
            const bdLng = z * Math.cos(theta) + 0.0065;
            const bdLat = z * Math.sin(theta) + 0.006;
            return [bdLng, bdLat];
        }

        function bd09ToGcj02(lng, lat) {
            const x = lng - 0.0065;
            const y = lat - 0.006;
            const z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
            const theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
            const gcjLng = z * Math.cos(theta);
            const gcjLat = z * Math.sin(theta);
            return [gcjLng, gcjLat];
        }

        function wgs84ToBd09(lng, lat) {
            const [gcjLng, gcjLat] = wgs84ToGcj02(lng, lat);
            return gcj02ToBd09(gcjLng, gcjLat);
        }

        function bd09ToWgs84(lng, lat) {
            const [gcjLng, gcjLat] = bd09ToGcj02(lng, lat);
            return gcj02ToWgs84(gcjLng, gcjLat);
        }
    </script>
</body>
</html>